﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using YLClient.Util;
using YLClient.YLServiceClient;
using YLPublicService.TransferModel;
using System.Linq;
using System.IO;
using System.Threading;


namespace YLClient.Froms
{

    public class WorkFlow
    {

        #region 局部变量
        /// <summary>
        /// 执行工作流的宿主
        /// </summary>
        NewItem host;
        /// <summary>
        /// 要添加的工作项
        /// </summary>
        WorkItem workItem;
        /// <summary>
        /// 要上传的文件
        /// </summary>
        string[] files;
        /// <summary>
        /// 上传失败的文件
        /// </summary>
        List<string> errFiles;
        #endregion

        #region 公开属性
        public event Action<ProcessPoint> StatusChange;
        public event Action<ProcessPoint> Started;
        public event Action<ProcessPoint> Finished;
        public event Action<ProcessPoint> OccurError;
        private ProcessPoint status;
        public ProcessPoint Status
        {
            get
            {
                return status;
            }
            set
            {
                status = value;
                if (StatusChange != null)
                {
                    StatusChange(value);
                }
            }
        }
        public ProcessPoint ErrorStatus { get; set; }

        ///<summary>
        /// 必须设置,默认为真
        /// </summary>
        public event Func<ProcessPoint, bool> ErrorContinueAt = p => true;

        #endregion

        public WorkFlow(WorkItem item, string[] files, NewItem host)
        {
            this.host = host;
            workItem = item;
            this.files = files;
            errFiles = new List<string>();
            Status = ProcessPoint.Ready;
        }

        #region 工作点方法实现

        void compressFile()
        {
            ImageProcessHelper imgProcesser = new ImageProcessHelper();
            var dir = imgProcesser.CompressImages(files);//耗时操作
            files = Common.getDirFiles(dir);
        }

        bool addWorkItem()
        {
            var client = ServiceClient.GetServiceClient();
            var itemID = client.AddWorkItem(workItem);
            workItem.WorkItemID = itemID;
            return itemID != 0;
        }
        /// <summary>
        /// 上传成功后清空Files 变量
        /// 上传失败后去除Files变量中的已成功项
        /// </summary>
        /// <returns></returns>
        bool uploadFiles()
        {
            ClientAdapter ftpClient = new ClientAdapter(false);
            ftpClient.OnTransferError +=
                fileName => errFiles.Add(fileName);
            var ret = ftpClient.UploadWorkItemFiles(workItem, files, 1);
            if (ret == false)
            {
                var successFiles = files.Except(errFiles);
                deleteTempFiles(successFiles);
                files = errFiles.ToArray();
            }
            else
                deleteTempFiles(files);
            return ret;
        }

        void deleteTempFiles(IEnumerable<string> files)
        {
            foreach (var file in files)
            {
                File.Delete(file);
            }
        }

        bool finishWorkItem()
        {
            var client = ServiceClient.GetServiceClient();
            return client.UpdatedWorkItemStatus(workItem, WorkItemStatus.WaitingProcess);
        }
        #endregion

        ProcessPoint CallProcessPoint(ProcessPoint point)
        {
            switch (point)
            {
                case ProcessPoint.CompressFiles:
                    compressFile();
                    return ProcessPoint.AddWorkItem;

                case ProcessPoint.AddWorkItem:
                    if (addWorkItem())
                        return ProcessPoint.AddFiles;
                    else
                        if (ErrorContinueAt(ProcessPoint.AddWorkItem))
                            return ProcessPoint.AddWorkItem;
                        else
                            return ProcessPoint.Error;
                case ProcessPoint.AddFiles:
                    if (uploadFiles())
                        return ProcessPoint.Succ;
                    else
                        if (ErrorContinueAt(ProcessPoint.AddFiles))
                            return ProcessPoint.AddFiles;
                        else
                            return ProcessPoint.Error;
                case ProcessPoint.Succ:
                    if (finishWorkItem())
                        return ProcessPoint.Ready;
                    else
                        if (ErrorContinueAt(ProcessPoint.Succ))
                            return ProcessPoint.Succ;
                        else
                            return ProcessPoint.Error;
                default:
                    throw new Exception("Not Exists ProcessPoint");
            }
        }

        public void Start()
        {
            Status = ProcessPoint.CompressFiles;
            if (Started != null)
            {
                Started(Status);
            }
            while (Status != ProcessPoint.Ready && Status != ProcessPoint.Error)
            {
                var nextProcessPoint = CallProcessPoint(Status);
                if (nextProcessPoint == ProcessPoint.Error)
                {
                    ErrorStatus = Status;
                    Status = ProcessPoint.Error;
                    break;
                }
                Status = nextProcessPoint;
            }
            if (Status == ProcessPoint.Ready)
            {
                if (Finished != null)
                {
                    Finished(Status);
                }
            }
            else
            {
                if (OccurError != null)
                {
                    OccurError(Status);
                }
            }
        }
    }

    /// <summary>
    /// Interaction logic for NewItem.xaml
    /// </summary>
  
}
